package com.hmall.search.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.sql.dialect.oracle.parser.OracleExprParser;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.common.constants.EsConstants;
import com.hmall.common.domain.PageDTO;
import com.hmall.common.utils.BeanUtils;
import com.hmall.search.domain.po.Item;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.domain.po.Search;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.mapper.SearchMapper;
import com.hmall.search.service.ISearchService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author 虎哥
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SearchServiceImpl extends ServiceImpl<SearchMapper, Search> implements ISearchService {

    /*
    es的初始化
     */
    private final RestHighLevelClient client=new RestHighLevelClient(
            RestClient.builder(
                    HttpHost.create("192.168.177.128:9200")
            )
    );

    private final ItemClient itemClient;

    /**
     * 搜索商品
     */
    @Override
    public PageDTO<ItemDTO> itemPageQuery(ItemPageQuery query)  {

        PageDTO<ItemDTO> result = new PageDTO<>();
//        System.out.println("query = " + query);
        //1.创建request请求
        SearchRequest request = new SearchRequest(EsConstants.INDEX_NAME);
        //2.准备参数 使用复合查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //2.1 根据名字模糊搜索
       if (query.getKey() != null && (! query.getKey().equals(""))){
           request.source().query(boolQuery.must(
                    QueryBuilders.matchQuery("name",query.getKey())
           ));
       }
        //2.2 根据品牌精确搜索
        if (query.getBrand() != null && (! query.getBrand().isBlank())){
            request.source().query(boolQuery.filter(
                    QueryBuilders.termQuery("brand",query.getBrand())
            ));
        }
        //2.3 根据分类精确搜索
        if (query.getCategory() != null  && (! query.getCategory().isBlank())){
            request.source().query(boolQuery.filter(
                    QueryBuilders.termQuery("category",query.getCategory())
            ));
        }
        //2.4 根据价格进行范围搜索
        if (query.getMinPrice() !=null || query.getMaxPrice() != null){
            request.source().query(boolQuery.filter(
                    QueryBuilders.rangeQuery("price")
                            .lte(query.getMaxPrice())
                            .gte(query.getMinPrice())
            ));
        }
        //2.5分页查询
        request.source().from((query.getPageNo()-1 )* query.getPageSize() ).size(query.getPageSize());
        //2.6排序
         if (query.getSortBy().equals("")){
             //如果没有传递排序参数，走默认排序
             request.source().sort(EsConstants.DEFAULT_SORT_BY,query.getIsAsc() ? SortOrder.ASC:SortOrder.DESC);
         }else {
             //传递的有参数，走参数排序
             request.source().sort(query.getSortBy(),query.getIsAsc() ? SortOrder.ASC:SortOrder.DESC);
         }
        try {
            //3.发送请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            //4.开始解析响应结果
            SearchHits hits = response.getHits(); //查询数据
            result.setTotal(hits.getTotalHits().value); //分页查询的总数
            long pages=0L;
            if (hits.getTotalHits().value % query.getPageSize() ==0 ){
                //整除
                pages=hits.getTotalHits().value/query.getPageSize();
            }else {
                //有余数 就页码加一 ，‘/’取最大整数 即 9/2 =4   + 1   共5页
                pages=hits.getTotalHits().value/query.getPageSize() + 1;
            }
            result.setPages(pages); //总页数
            SearchHit[] searchHits = hits.getHits();  //该数组是查询的真正的数据集
            List<ItemDTO> list=new ArrayList<>();  //用来存储分页查询的数据
            if (searchHits != null && searchHits.length != 0){
                for (SearchHit searchHit : searchHits) {
                    String json = searchHit.getSourceAsString();  //当前是一条itemDoc的json格式字符串
                  //将json字符串转为Bean类
//                    ItemDTO itemDTO = JSONUtil.toBean(json, ItemDTO.class);
                    Item item = JSONUtil.toBean(json, Item.class);
//                    System.out.println("item = " + item);
                    //调用商品微服务，根据id查询数据
                    ItemDTO itemDTO = itemClient.queryItemById(item.getId());
                    //存入集合中
                    list.add(itemDTO);
                }
            }
            result.setList(list);
        } catch (IOException e) {
            log.error("使用es查询失败！！！");
            throw new RuntimeException(e);
        }
        //返回分页结果
        return result;
    }

    /**
     * 根据id搜索商品
     * 即查询当前id的文档
     * @param id
     * @return
     */
    @Override
    public ItemDTO searchById(Long id) throws IOException {

        String sid = id.toString();
        //1.创建请求
      GetRequest request=new GetRequest(EsConstants.INDEX_NAME,sid);
      //2.发送请求
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        //解析响应结果
        String json = response.getSourceAsString();
        //将字符串转为Bean类
        return  JSONUtil.toBean(json, ItemDTO.class);
    }

    /**
     * 使用es中的聚合
     * @param query
     */
    @Override
    public  Map<String, List<String>> filters(ItemPageQuery query) throws IOException {
        //1.创建SearchRequest请求对象
        SearchRequest request=new SearchRequest(EsConstants.INDEX_NAME);
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        //2.准备参数
        if (StrUtil.isNotBlank(query.getKey())) {
            queryBuilder.must(QueryBuilders.matchQuery("name", query.getKey()));
        }
        if (StrUtil.isNotBlank(query.getBrand())) {
            queryBuilder.filter(QueryBuilders.termQuery("brand", query.getBrand()));
        }
        if (StrUtil.isNotBlank(query.getCategory())) {
            queryBuilder.filter(QueryBuilders.matchQuery("category", query.getCategory()));
        }
        if (query.getMaxPrice() != null) {
            queryBuilder.filter(QueryBuilders.rangeQuery("price").gte(query.getMinPrice()).lte(query.getMaxPrice()));
        }

        //2.2使用聚合
        //根据品牌 分类进行分组
        String categoryAgg = "category_agg";
        String brandAgg = "brand_agg";
        request.source()
                .query(queryBuilder)
                .aggregation(AggregationBuilders.terms(categoryAgg).field("category"))
                .aggregation(AggregationBuilders.terms(brandAgg).field("brand"));

        //3发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //4.解析响应结果
        Map<String, List<String>> resultMap = new HashMap<>();
        Terms terms = response.getAggregations().get(categoryAgg);
        if (terms != null) {
            resultMap.put("category",terms.getBuckets().stream().map(MultiBucketsAggregation.Bucket::getKeyAsString).collect(Collectors.toList()));
        }
        terms = response.getAggregations().get(brandAgg);
        if (terms != null) {
            resultMap.put("brand",terms.getBuckets().stream().map(MultiBucketsAggregation.Bucket::getKeyAsString).collect(Collectors.toList()));
        }

        // 封装并返回
        return resultMap;
    }
}
